Skip to content
字数
1449 字
阅读时间
6 分钟

Vue 2 和 Vue 3 的 diff 算法在核心目标(高效更新 DOM)上一致,但实现思路和性能表现有显著差异,主要体现在对比策略、优化方向和细节处理上。以下从原理和差异两方面展开说明:

一、核心原理:diff 算法的本质

diff 算法是虚拟 DOM(VNode)的核心机制,用于对比新旧 VNode 树的差异,只更新变化的部分到真实 DOM,避免全量重渲染。其核心步骤包括:

  1. 同级对比:只对比同一层级的 VNode(不跨层级对比,降低复杂度)。
  2. 标签判断:若标签不同,直接销毁旧节点并创建新节点。
  3. 标签相同:对比属性、文本、子节点等细节差异,局部更新。

二、Vue 2 的 diff 算法

Vue 2 采用双指针遍历对比的策略,核心逻辑基于 Snabbdom 库的实现,复杂度为 O(n²)(极端情况)。

1. 核心流程:

  • 同级子节点对比:对新旧子节点数组,用两个指针(旧节点的 startIdx/endIdx 和新节点的 startIdx/endIdx)从两端向中间遍历。
  • 四种命中情况
    • 旧头 vs 新头(索引相同的节点)
    • 旧尾 vs 新尾
    • 旧头 vs 新尾(节点复用,需移动位置)
    • 旧尾 vs 新头(节点复用,需移动位置)
  • 未命中情况
    • 若以上四种都不命中,会遍历旧节点列表,用新节点的 key 查找可复用的旧节点。
    • 若找到,移动节点到对应位置;若未找到,创建新节点。
  • 处理剩余节点:若新节点有剩余,批量创建;若旧节点有剩余,批量删除。

2. 问题与局限:

  • 依赖 key 的准确性:若 key 重复或不稳定(如用索引作为 key),会导致节点复用错误,引发 DOM 异常。
  • 性能瓶颈:当子节点数量庞大(如长列表),双指针遍历和全量查找会导致性能下降(O(n²) 复杂度)。
  • 移动逻辑复杂:需要频繁调整指针和节点位置,逻辑冗余。

三、Vue 3 的 diff 算法

Vue 3 对 diff 算法进行了彻底重构,核心优化是引入“最长递增子序列”(LIS),降低了移动节点的次数,复杂度优化为 O(n log n)

1. 核心流程:

  • 前置处理
    • 先对比新旧子节点数组的前缀相同节点(从头部开始,key 和标签都相同),直接复用。
    • 再对比后缀相同节点(从尾部开始),直接复用。
  • 处理中间差异部分
    • 若剩余新节点为空:删除旧节点中剩余的部分。
    • 若剩余旧节点为空:创建新节点中剩余的部分。
    • 若两者都不为空:
      • 新节点的 key 建立映射表keyToNewIndexMap),快速查找旧节点中可复用的节点。
      • 遍历旧节点剩余部分,标记可复用节点的新索引位置,生成 source 数组(记录旧节点在新数组中的位置)。
      • 计算 source 数组的最长递增子序列(LIS):该序列对应的节点无需移动,其他节点基于 LIS 插入到正确位置,减少移动次数。

2. 关键优化:

  • LIS 减少移动:通过数学方法找到无需移动的节点序列,其他节点只需插入到序列周围,避免了 Vue 2 中频繁的位置调整。
  • 哈希表加速查找:用 key 映射新节点索引,替代 Vue 2 中的全量遍历,查找效率从 O(n) 提升到 O(1)。
  • 边界情况优化:对无 key 的节点(如文本节点)单独处理,避免错误复用。
  • 复杂度降低:从 O(n²) 优化为 O(n log n),在长列表场景下性能提升显著。

四、核心差异对比

维度Vue 2 diff 算法Vue 3 diff 算法
核心策略双指针从两端向中间遍历前缀/后缀对比 + 最长递增子序列(LIS)
时间复杂度O(n²)(极端情况)O(n log n)
查找效率遍历旧节点查找可复用节点(O(n))哈希表映射(O(1))
节点移动逻辑依赖指针调整,移动次数较多基于 LIS 减少移动,只插入差异节点
长列表性能性能较差(大量遍历和移动)性能优异(复杂度降低)
key 的依赖依赖较强,key 不当易出错优化了无 key 场景,key 作用更稳定

五、总结

Vue 3 的 diff 算法通过前缀/后缀快速复用、哈希表加速查找、LIS 减少移动三大优化,解决了 Vue 2 在长列表场景下的性能瓶颈,同时简化了逻辑复杂度。核心差异本质是:Vue 2 侧重“遍历对比”,而 Vue 3 侧重“数学优化 + 哈希加速”,在保持虚拟 DOM 优势的同时,大幅提升了更新效率。

贡献者

The avatar of contributor named as jiechen jiechen

页面历史

撰写